/*
 * Copyright 2007-2008 Michele Mostarda ( michele.mostarda@gmail.com ).
 * All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the 'License');
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an 'AS IS' BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package org.asemantics.anthill.chatconsole;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.Target;
import org.asemantics.anthill.End;
import org.asemantics.anthill.Inspect;
import org.asemantics.anthill.Invoke;

import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

/**
 * This class implements the {@link org.asemantics.anthill.chatconsole.CommandsProvider}
 * to return as commands the targets exposed by the associated {@link org.apache.tools.ant.Project}.
 */
public class TargetsCommandsProvider implements CommandsProvider {

    /**
     * Groups informations related to a command.
     */
    class CommandEntry {

        /**
         * The command short description.
         */
        private final String shortDescription;

        /**
         * The command long description.
         */
        private final String longDescription;

        /**
         * The command associated to the entry.
         */
        private final Command command;

        CommandEntry(String sd, String ld, Command cmd) {
            shortDescription = sd;
            longDescription  = ld;
            command          = cmd;
        }

        public String getShortDescription() {
            return shortDescription;
        }

        public String getLongDescription() {
            return longDescription;
        }

        public Command getCommand() {
            return command;
        }

    }

    private Map<String, CommandEntry> commandEntries;

    private String[] commandNames;

    public TargetsCommandsProvider(Project project) {
        if(project == null) {
            throw new NullPointerException();
        }

        // No status info is mantained in the current version so a single instance
        // is enough.
        final Invoke invokeInstance = new Invoke();

        // Create command name descriptions map.
        commandEntries = new HashMap();
        Hashtable<String, Target> targets = project.getTargets();
        String targetDescription;
        int splitpoint;
        for( String target : targets.keySet() ) {

            // Extracts short and long descripion for the target.
            String shortDescription, longDescription;
            shortDescription = longDescription = "<no description>";
            targetDescription = targets.get(target).getDescription();
            if(targetDescription != null) {
                splitpoint = targetDescription.indexOf(".");
                if(splitpoint != -1 && splitpoint != targetDescription.length() -1) {
                    shortDescription = targetDescription.substring(0, splitpoint);
                    longDescription  = targetDescription.substring(splitpoint);
                } else {
                    shortDescription = longDescription = targetDescription;
                }
            }

            // Registers the command entry.
            commandEntries.put(
                    target,
                    new CommandEntry( shortDescription, longDescription, invokeInstance)
            );
        }

        // Add meta commands.
        addMetaCommands(commandEntries);
        
        // Create command name array.
        commandNames = commandEntries.keySet().toArray( new String[commandEntries.keySet().size()] );
    }

    /**
     * Adds the meta command to the entries list.
     *
     * @param ce
     */
    protected void addMetaCommands(Map<String,CommandEntry> ce) {
        // Registers the end command.
        CommandEntry endCommandEntry = new CommandEntry(
                "Closeup the listener.",
                "Forces the listener to interrupt to shut down.",
                new End()
        );
        // Registers the inspect command.
        CommandEntry inspectCommandEntry = new CommandEntry(
                "List the exposed commands.",
                "Lists the commands exposed by the listener.",
                new Inspect()
        );

        ce.put("end",     endCommandEntry);
        ce.put("inspect", inspectCommandEntry);
    }

    public String[] getCommandNames() {
        return commandNames;
    }

    public Command getCommand(String commandName) {
        CommandEntry commandEntry = commandEntries.get(commandName);
        if(commandEntry == null) {
            throw new IllegalArgumentException("Command '" + commandName + "' is not defined.");
        }
        return commandEntry.getCommand();
    }

    public boolean isCommandName(String commandName) {
        return commandEntries.containsKey(commandName);
    }

    public String getCommandShortDescription(String commandName) {
        CommandEntry commandEntry = commandEntries.get(commandName);
        if(commandEntry == null) {
            throw new IllegalArgumentException("Cannot find entry for command: '" + commandName + "'.");
        }
        return commandEntry.getShortDescription();
    }

    public String getCommandLongDescription(String commandName) {
        CommandEntry commandEntry = commandEntries.get(commandName);
        if(commandEntry == null) {
            throw new IllegalArgumentException("Cannot find entry for command: '" + commandName + "'.");
        }
        return commandEntry.getLongDescription();
    }
}
